#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "drv_cesa_ioctl.h"
#include "crypto_firm/crypto_api_aes.h"
#include "crypto_firm/crypto_api_des.h"
#include "types/vmm_api.h"

void SELFKEY_TEST(FH_CESA_ADES_ALGO_MODE_E algo_mode, FH_CESA_ADES_WORK_MODE_E work_mode, uint8_t efusekey[])
{
	uint8_t aes_key[32];
	uint8_t aes_iv[16];
	uint32_t length = 1024*1024;
	uint8_t *input_data_vir;
	uint8_t *hw_data_vir;
	uint8_t *sw_data;
	uint8_t sw_aes_iv[16];
	char *str_algo_mode;
	char *str_work_mode;
	uint8_t self_key_sw[32];
	uint8_t self_key_hw[32] = {0x35, 0x46, 0x28, 0x79,
							0x72, 0x89, 0x67, 0x73,
							0x21, 0x57, 0x80, 0x76,
							0x54, 0x70, 0x83, 0x60,
							0x11, 0x22, 0x33, 0x44,
							0x55, 0x66, 0x77, 0x88,
							0x99, 0xaa, 0xbb, 0xcc,
							0xdd, 0xee, 0xff, 0x44};

	//===================data prepare===================
	switch (algo_mode) {
	case FH_CESA_ADES_ALGO_MODE_AES128:
		str_algo_mode = "aes128";
		break;
	case FH_CESA_ADES_ALGO_MODE_AES192:
		str_algo_mode = "aes192";
		break;
	case FH_CESA_ADES_ALGO_MODE_AES256:
		str_algo_mode = "aes256";
		break;
	default:
		printf("AES_TEST algorithm mode illegal\n");
		return;
	}

	switch (work_mode) {
	case FH_CESA_ADES_WORK_MODE_ECB:
		str_work_mode = "ecb";
		break;
	case FH_CESA_ADES_WORK_MODE_CBC:
		str_work_mode = "cbc";
		break;
	case FH_CESA_AES_WORK_MODE_CTR:
		str_work_mode = "ctr";
		break;
	case FH_CESA_ADES_WORK_MODE_CFB8:
		str_work_mode = "cfb8";
		break;
	case FH_CESA_ADES_WORK_MODE_OFB:
		str_work_mode = "ofb";
		break;
	default:
		printf("AES_TEST work mode illegal\n");
		return;
	}

	input_data_vir = malloc(length);
	hw_data_vir = malloc(length);
	sw_data = malloc(length);

	if (efusekey)
		memcpy(aes_key, efusekey, 32);
	else
		FH_UNF_CESA_Gen_Random_Bytes(32, aes_key);
	FH_UNF_CESA_Gen_Random_Bytes(16, aes_iv);
	FH_UNF_CESA_Gen_Random_Bytes(length, input_data_vir);
	memcpy(sw_data, input_data_vir, length);
	memcpy(sw_aes_iv, aes_iv, 16);
	memcpy(self_key_sw, self_key_hw, 32);

	//===================C code===================
	PCRYPTO_BLOCK_CIPHER c_aes = 0;
	CRYPTO_AES128_CONTEX aes128;
	CRYPTO_AES192_CONTEX aes192;
	CRYPTO_AES256_CONTEX aes256;

	switch (algo_mode) {
	case FH_CESA_ADES_ALGO_MODE_AES128:
		CRYPTO_API_aes128_init(&aes128);
		c_aes = &(aes128.c);
		c_aes->set_key(c_aes, aes_key, 16);
		c_aes->buf = sw_aes_iv;
		break;
	case FH_CESA_ADES_ALGO_MODE_AES192:
		CRYPTO_API_aes192_init(&aes192);
		c_aes = &(aes192.c);
		c_aes->set_key(c_aes, aes_key, 24);
		c_aes->buf = sw_aes_iv;
		break;
	case FH_CESA_ADES_ALGO_MODE_AES256:
		CRYPTO_API_aes256_init(&aes256);
		c_aes = &(aes256.c);
		c_aes->set_key(c_aes, aes_key, 32);
		c_aes->buf = sw_aes_iv;
		break;
	default:
		break;
	}

	switch (work_mode) {
	case FH_CESA_ADES_WORK_MODE_ECB:
		CRYPTO_API_aes_ecb_decrypt(c_aes, self_key_sw, 0x20);
		break;
	case FH_CESA_ADES_WORK_MODE_CBC:
		CRYPTO_API_aes_cbc_decrypt(c_aes, self_key_sw, 0x20);
		break;
	case FH_CESA_AES_WORK_MODE_CTR:
		CRYPTO_API_aes_ctr_decrypt(c_aes, self_key_sw, 0x20);
		break;
	case FH_CESA_ADES_WORK_MODE_CFB8:
		CRYPTO_API_aes_cfb8_decrypt(c_aes, self_key_sw, 0x20);
		break;
	case FH_CESA_ADES_WORK_MODE_OFB:
		CRYPTO_API_aes_ofb128_decrypt(c_aes, self_key_sw, 0x20);
		break;
	default:
		break;
	}

	switch (algo_mode) {
	case FH_CESA_ADES_ALGO_MODE_AES128:
		CRYPTO_API_aes128_init(&aes128);
		c_aes = &(aes128.c);
		c_aes->set_key(c_aes, self_key_sw, 16);
		memcpy(sw_aes_iv, aes_iv, 16);
		c_aes->buf = sw_aes_iv;
		break;
	case FH_CESA_ADES_ALGO_MODE_AES192:
		CRYPTO_API_aes192_init(&aes192);
		c_aes = &(aes192.c);
		c_aes->set_key(c_aes, self_key_sw, 24);
		memcpy(sw_aes_iv, aes_iv, 16);
		c_aes->buf = sw_aes_iv;
		break;
	case FH_CESA_ADES_ALGO_MODE_AES256:
		CRYPTO_API_aes256_init(&aes256);
		c_aes = &(aes256.c);
		c_aes->set_key(c_aes, self_key_sw, 32);
		memcpy(sw_aes_iv, aes_iv, 16);
		c_aes->buf = sw_aes_iv;
		break;
	default:
		break;
	}

	switch (work_mode) {
	case FH_CESA_ADES_WORK_MODE_ECB:
		CRYPTO_API_aes_ecb_decrypt(c_aes, sw_data, length);
		break;
	case FH_CESA_ADES_WORK_MODE_CBC:
		CRYPTO_API_aes_cbc_decrypt(c_aes, sw_data, length);
		break;
	case FH_CESA_AES_WORK_MODE_CTR:
		CRYPTO_API_aes_ctr_decrypt(c_aes, sw_data, length);
		break;
	case FH_CESA_ADES_WORK_MODE_CFB8:
		CRYPTO_API_aes_cfb8_decrypt(c_aes, sw_data, length);
		break;
	case FH_CESA_ADES_WORK_MODE_OFB:
		CRYPTO_API_aes_ofb128_decrypt(c_aes, sw_data, length);
		break;
	default:
		break;
	}

	//===================HW code===================
	uint32_t session;

	FH_UNF_CESA_Open();
	FH_UNF_CESA_ADES_Create(&session);
	FH_UNF_CESA_ADES_Addr_Attr(session,
				FH_CESA_ADES_ADDR_ATTR_VIR,
				FH_CESA_ADES_ADDR_ATTR_VIR);

	FH_CESA_ADES_CTRL_S ctrl;

	ctrl.algo_mode = algo_mode;
	ctrl.work_mode = work_mode;
	ctrl.oper_mode = FH_CESA_ADES_OPER_MODE_DECRYPT;
	ctrl.self_key_gen = true;
	memcpy(ctrl.self_key_text, self_key_hw, 32);
	if (efusekey)
		ctrl.enKeySrc = FH_CESA_ADES_KEY_SRC_EFUSE;
	else {
		ctrl.enKeySrc = FH_CESA_ADES_KEY_SRC_USER;
		memcpy(ctrl.key, aes_key, 32);
	}
	memcpy(ctrl.iv, aes_iv, 16);
	FH_UNF_CESA_ADES_Config(session, &ctrl);
	FH_UNF_CESA_ADES_Process(session, (uint32_t)input_data_vir, (uint32_t)hw_data_vir, length);

	if (memcmp(hw_data_vir, sw_data, length) != 0)
		printf("self_key_gen : %s : %s dec failed!\n", str_algo_mode, str_work_mode);
	else
		printf("self_key_gen : %s : %s dec successful!\n", str_algo_mode, str_work_mode);

	FH_UNF_CESA_ADES_Destroy(session);
	FH_UNF_CESA_Close();

	free(input_data_vir);
	free(hw_data_vir);
	free(sw_data);
}

void AES_TEST(FH_CESA_ADES_ALGO_MODE_E algo_mode, FH_CESA_ADES_WORK_MODE_E work_mode, uint8_t efusekey[])
{
	uint8_t aes_key[32];
	uint8_t aes_iv[16];
	uint32_t length = 1024*1024;
	//uint8_t *input_data_phy;
	uint8_t *input_data_vir;
	//uint8_t *hw_data_phy;
	uint8_t *hw_data_vir;
	uint8_t *sw_data;
	uint8_t sw_aes_iv[16];
	char *str_algo_mode;
	char *str_work_mode;


	//===================data prepare===================
	switch(algo_mode)
	{
	case FH_CESA_ADES_ALGO_MODE_AES128:
		str_algo_mode = "aes128";
		break;
	case FH_CESA_ADES_ALGO_MODE_AES192:
		str_algo_mode = "aes192";
		break;
	case FH_CESA_ADES_ALGO_MODE_AES256:
		str_algo_mode = "aes256";
		break;
	default:
		printf("AES_TEST algorithm mode illegal\n");
		return;
	}

	switch(work_mode)
	{
	case FH_CESA_ADES_WORK_MODE_ECB:
		str_work_mode = "ecb";
		break;
	case FH_CESA_ADES_WORK_MODE_CBC:
		str_work_mode = "cbc";
		break;
	case FH_CESA_AES_WORK_MODE_CTR:
		str_work_mode = "ctr";
		break;
	case FH_CESA_ADES_WORK_MODE_CFB8:
		str_work_mode = "cfb8";
		break;
	case FH_CESA_ADES_WORK_MODE_OFB:
		str_work_mode = "ofb";
		break;
	default:
		printf("AES_TEST work mode illegal\n");
		return;
	}

	input_data_vir = malloc(length);
	hw_data_vir = malloc(length);
	sw_data = malloc(length);

	if (efusekey)
		memcpy(aes_key, efusekey, 32);
	else
		FH_UNF_CESA_Gen_Random_Bytes(32, aes_key);
	FH_UNF_CESA_Gen_Random_Bytes(16, aes_iv);
	FH_UNF_CESA_Gen_Random_Bytes(length, input_data_vir);

	memcpy(sw_data, input_data_vir, length);
	memcpy(sw_aes_iv, aes_iv, 16);



	//===================C code===================
	PCRYPTO_BLOCK_CIPHER c_aes = 0;
	CRYPTO_AES128_CONTEX aes128;
	CRYPTO_AES192_CONTEX aes192;
	CRYPTO_AES256_CONTEX aes256;

	switch(algo_mode)
	{
	case FH_CESA_ADES_ALGO_MODE_AES128:
		CRYPTO_API_aes128_init(&aes128);
		c_aes = &(aes128.c);
		c_aes->set_key(c_aes, aes_key,16);
		c_aes->buf = sw_aes_iv;
		break;
	case FH_CESA_ADES_ALGO_MODE_AES192:
		CRYPTO_API_aes192_init(&aes192);
		c_aes = &(aes192.c);
		c_aes->set_key(c_aes, aes_key,24);
		c_aes->buf = sw_aes_iv;
		break;
	case FH_CESA_ADES_ALGO_MODE_AES256:
		CRYPTO_API_aes256_init(&aes256);
		c_aes = &(aes256.c);
		c_aes->set_key(c_aes, aes_key,32);
		c_aes->buf = sw_aes_iv;
		break;
	default:
		break;
	}

	switch(work_mode)
	{
	case FH_CESA_ADES_WORK_MODE_ECB:
		CRYPTO_API_aes_ecb_encrypt(c_aes, sw_data, length);
		break;
	case FH_CESA_ADES_WORK_MODE_CBC:
		CRYPTO_API_aes_cbc_encrypt(c_aes, sw_data, length);
		break;
	case FH_CESA_AES_WORK_MODE_CTR:
		CRYPTO_API_aes_ctr_encrypt(c_aes, sw_data, length);
		break;
	case FH_CESA_ADES_WORK_MODE_CFB8:
		CRYPTO_API_aes_cfb8_encrypt(c_aes, sw_data, length);
		break;
	case FH_CESA_ADES_WORK_MODE_OFB:
		CRYPTO_API_aes_ofb128_encrypt(c_aes, sw_data, length);
		break;
	default:
		break;
	}



	//===================HW code===================
	uint32_t session;

	FH_UNF_CESA_Open();
	FH_UNF_CESA_ADES_Create(&session);
	FH_UNF_CESA_ADES_Addr_Attr(session,
				FH_CESA_ADES_ADDR_ATTR_VIR,
				FH_CESA_ADES_ADDR_ATTR_VIR);

	FH_CESA_ADES_CTRL_S ctrl;

	ctrl.algo_mode = algo_mode;
	ctrl.work_mode = work_mode;
	ctrl.oper_mode = FH_CESA_ADES_OPER_MODE_ENCRYPT;
	ctrl.self_key_gen = false;
	if (efusekey)
		ctrl.enKeySrc = FH_CESA_ADES_KEY_SRC_EFUSE;
	else {
		ctrl.enKeySrc = FH_CESA_ADES_KEY_SRC_USER;
		memcpy(ctrl.key, aes_key, 32);
	}
	memcpy(ctrl.iv, aes_iv, 16);
	FH_UNF_CESA_ADES_Config(session, &ctrl);
	FH_UNF_CESA_ADES_Process(session, (uint32_t)input_data_vir, (uint32_t)hw_data_vir, length);

	if (memcmp(hw_data_vir, sw_data, length) != 0)
		printf("%s : %s enc failed!\n", str_algo_mode, str_work_mode);
	else
		printf("%s : %s enc successful!\n", str_algo_mode, str_work_mode);

	ctrl.oper_mode = FH_CESA_ADES_OPER_MODE_DECRYPT;
	FH_UNF_CESA_ADES_Config(session, &ctrl);
	FH_UNF_CESA_ADES_Process(session, (uint32_t)hw_data_vir, (uint32_t)hw_data_vir, length);

	if (memcmp(hw_data_vir, input_data_vir, length) != 0)
		printf("%s : %s dec failed!\n", str_algo_mode, str_work_mode);
	else
		printf("%s : %s dec successful!\n", str_algo_mode, str_work_mode);

	FH_UNF_CESA_ADES_Destroy(session);
	FH_UNF_CESA_Close();

	free(input_data_vir);
	free(hw_data_vir);
	free(sw_data);
}

void DES_TEST(FH_CESA_ADES_ALGO_MODE_E algo_mode, FH_CESA_ADES_WORK_MODE_E work_mode, uint8_t efusekey[])
{
	uint8_t des_key[24];
	uint8_t des_iv[8];
	uint32_t length = 1024*1024;
	//uint8_t *input_data_phy;
	uint8_t *input_data_vir;
	//uint8_t *hw_data_phy;
	uint8_t *hw_data_vir;
	uint8_t *sw_data;
	uint8_t sw_des_iv[8];
	char *str_algo_mode;
	char *str_work_mode;


	//===================data prepare===================
	switch(algo_mode)
	{
	case FH_CESA_ADES_ALGO_MODE_DES:
		str_algo_mode = "des";
		break;
	case FH_CESA_ADES_ALGO_MODE_TDES:
		str_algo_mode = "tdes";
		break;
	default:
		printf("DES_TEST algorithm mode illegal\n");
		return;
	}

	switch(work_mode)
	{
	case FH_CESA_ADES_WORK_MODE_ECB:
		str_work_mode = "ecb";
		break;
	case FH_CESA_ADES_WORK_MODE_CBC:
		str_work_mode = "cbc";
		break;
	case FH_CESA_ADES_WORK_MODE_CFB8:
		str_work_mode = "cfb8";
		break;
	case FH_CESA_ADES_WORK_MODE_OFB:
		str_work_mode = "ofb";
		break;
	default:
		printf("DES_TEST work mode illegal\n");
		return;
	}

	input_data_vir = malloc(length);
	hw_data_vir = malloc(length);
	sw_data = malloc(length);

	if (efusekey)
		memcpy(des_key, efusekey, 24);
	else
		FH_UNF_CESA_Gen_Random_Bytes(24, des_key);
	FH_UNF_CESA_Gen_Random_Bytes(8, des_iv);
	FH_UNF_CESA_Gen_Random_Bytes(length, input_data_vir);

	memcpy(sw_data, input_data_vir, length);
	memcpy(sw_des_iv, des_iv, 8);

	//===================C code===================
	CRYPTO_DES_CONTEX des;
	PCRYPTO_DES_BLOCK_CIPHER c_des = 0;

	if( algo_mode == FH_CESA_ADES_ALGO_MODE_DES ) {
		CRYPTO_API_des_init(&des);
		c_des = &(des.c);
		c_des->set_key(c_des, des_key,des_key,des_key,DES_ENCRYPT);
		c_des->buf = sw_des_iv;
	} else {
		CRYPTO_API_tdes_init(&des);
		c_des = &(des.c);
		c_des->set_key(c_des, des_key,des_key+8,des_key+16,DES_ENCRYPT);
		c_des->buf = sw_des_iv;
	}

	switch(work_mode)
	{
	case FH_CESA_ADES_WORK_MODE_ECB:
		CRYPTO_API_des_ecb_encrypt(c_des, sw_data, length);
		break;
	case FH_CESA_ADES_WORK_MODE_CBC:
		CRYPTO_API_des_cbc_encrypt(c_des, sw_data, length);
		break;
	case FH_CESA_ADES_WORK_MODE_CFB8:
		CRYPTO_API_des_cfb8_encrypt(c_des, sw_data, length);
		break;
	case FH_CESA_ADES_WORK_MODE_OFB:
		CRYPTO_API_des_ofb64_encrypt(c_des, sw_data, length);
		break;
	default:
		break;
	}

	//===================HW code===================
	uint32_t session;

	FH_UNF_CESA_Open();
	FH_UNF_CESA_ADES_Create(&session);
	FH_UNF_CESA_ADES_Addr_Attr(session,
				FH_CESA_ADES_ADDR_ATTR_VIR,
				FH_CESA_ADES_ADDR_ATTR_VIR);

	FH_CESA_ADES_CTRL_S ctrl;

	ctrl.algo_mode = algo_mode;
	ctrl.work_mode = work_mode;
	ctrl.oper_mode = FH_CESA_ADES_OPER_MODE_ENCRYPT;
	ctrl.self_key_gen = false;
	if (efusekey)
		ctrl.enKeySrc = FH_CESA_ADES_KEY_SRC_EFUSE;
	else {
		ctrl.enKeySrc = FH_CESA_ADES_KEY_SRC_USER;
		memcpy(ctrl.key, des_key, 24);
	}
	memcpy(ctrl.iv, des_iv, 8);
	FH_UNF_CESA_ADES_Config(session, &ctrl);
	FH_UNF_CESA_ADES_Process(session, (uint32_t)input_data_vir, (uint32_t)hw_data_vir, length);

	if (memcmp(hw_data_vir, sw_data, length) != 0)
		printf("%s : %s enc failed!\n", str_algo_mode, str_work_mode);
	else
		printf("%s : %s enc successful!\n", str_algo_mode, str_work_mode);

	ctrl.oper_mode = FH_CESA_ADES_OPER_MODE_DECRYPT;
	FH_UNF_CESA_ADES_Config(session, &ctrl);
	FH_UNF_CESA_ADES_Process(session, (uint32_t)hw_data_vir, (uint32_t)hw_data_vir, length);

	if (memcmp(hw_data_vir, input_data_vir, length) != 0)
		printf("%s : %s dec failed!\n", str_algo_mode, str_work_mode);
	else
		printf("%s : %s dec successful!\n", str_algo_mode, str_work_mode);

	FH_UNF_CESA_ADES_Destroy(session);
	FH_UNF_CESA_Close();

	free(input_data_vir);
	free(hw_data_vir);
	free(sw_data);
}

void AES_PHY_TEST(FH_CESA_ADES_ALGO_MODE_E algo_mode,
		FH_CESA_ADES_WORK_MODE_E work_mode,
		uint8_t efusekey[])
{
	uint8_t aes_key[32];
	uint8_t aes_iv[16];
	uint32_t length = 1024*1024;

	uint8_t *input_data_vir;
	uint32_t input_data_phy;

	uint8_t *hw_data_vir;
	uint32_t hw_data_phy;

	uint8_t *sw_data;
	uint8_t sw_aes_iv[16];
	char *str_algo_mode;
	char *str_work_mode;


	//===================data prepare===================
	switch (algo_mode) {
	case FH_CESA_ADES_ALGO_MODE_AES128:
		str_algo_mode = "aes128";
		break;
	case FH_CESA_ADES_ALGO_MODE_AES192:
		str_algo_mode = "aes192";
		break;
	case FH_CESA_ADES_ALGO_MODE_AES256:
		str_algo_mode = "aes256";
		break;
	default:
		printf("AES_TEST algorithm mode illegal\n");
		return;
	}

	switch (work_mode) {
	case FH_CESA_ADES_WORK_MODE_ECB:
		str_work_mode = "ecb";
		break;
	case FH_CESA_ADES_WORK_MODE_CBC:
		str_work_mode = "cbc";
		break;
	case FH_CESA_AES_WORK_MODE_CTR:
		str_work_mode = "ctr";
		break;
	case FH_CESA_ADES_WORK_MODE_CFB8:
		str_work_mode = "cfb8";
		break;
	case FH_CESA_ADES_WORK_MODE_OFB:
		str_work_mode = "ofb";
		break;
	default:
		printf("AES_TEST work mode illegal\n");
		return;
	}


	sw_data = malloc(length);
	if (FH_SYS_VmmAlloc(&input_data_phy,
		(void **)(&input_data_vir),
		"aes_data", "", length)
		|| NULL == input_data_vir) {
		printf("Error: malloc input_data vmm size: %dB failed.\n", length);
		return;
	}
	memset(input_data_vir, 0, length);

	if (FH_SYS_VmmAlloc(&hw_data_phy,
		(void **)(&hw_data_vir),
		"aes_data", "", length)
		|| NULL == hw_data_vir) {
		printf("Error: malloc hw_data vmm size: %dB failed.\n", length);
		return;
	}
	memset(hw_data_vir, 0, length);


	if (efusekey)
		memcpy(aes_key, efusekey, 32);
	else
		FH_UNF_CESA_Gen_Random_Bytes(32, aes_key);
	FH_UNF_CESA_Gen_Random_Bytes(16, aes_iv);
	FH_UNF_CESA_Gen_Random_Bytes(length, input_data_vir);

	memcpy(sw_data, input_data_vir, length);
	memcpy(sw_aes_iv, aes_iv, 16);



	//===================C code===================
	PCRYPTO_BLOCK_CIPHER c_aes = 0;
	CRYPTO_AES128_CONTEX aes128;
	CRYPTO_AES192_CONTEX aes192;
	CRYPTO_AES256_CONTEX aes256;

	switch (algo_mode) {
	case FH_CESA_ADES_ALGO_MODE_AES128:
		CRYPTO_API_aes128_init(&aes128);
		c_aes = &(aes128.c);
		c_aes->set_key(c_aes, aes_key, 16);
		c_aes->buf = sw_aes_iv;
		break;
	case FH_CESA_ADES_ALGO_MODE_AES192:
		CRYPTO_API_aes192_init(&aes192);
		c_aes = &(aes192.c);
		c_aes->set_key(c_aes, aes_key, 24);
		c_aes->buf = sw_aes_iv;
		break;
	case FH_CESA_ADES_ALGO_MODE_AES256:
		CRYPTO_API_aes256_init(&aes256);
		c_aes = &(aes256.c);
		c_aes->set_key(c_aes, aes_key, 32);
		c_aes->buf = sw_aes_iv;
		break;
	default:
		break;
	}

	switch (work_mode) {
	case FH_CESA_ADES_WORK_MODE_ECB:
		CRYPTO_API_aes_ecb_encrypt(c_aes, sw_data, length);
		break;
	case FH_CESA_ADES_WORK_MODE_CBC:
		CRYPTO_API_aes_cbc_encrypt(c_aes, sw_data, length);
		break;
	case FH_CESA_AES_WORK_MODE_CTR:
		CRYPTO_API_aes_ctr_encrypt(c_aes, sw_data, length);
		break;
	case FH_CESA_ADES_WORK_MODE_CFB8:
		CRYPTO_API_aes_cfb8_encrypt(c_aes, sw_data, length);
		break;
	case FH_CESA_ADES_WORK_MODE_OFB:
		CRYPTO_API_aes_ofb128_encrypt(c_aes, sw_data, length);
		break;
	default:
		break;
	}



	//===================HW code===================
	uint32_t session;

	FH_UNF_CESA_Open();
	FH_UNF_CESA_ADES_Create(&session);
	FH_UNF_CESA_ADES_Addr_Attr(session,
				FH_CESA_ADES_ADDR_ATTR_PHY,
				FH_CESA_ADES_ADDR_ATTR_PHY);

	FH_CESA_ADES_CTRL_S ctrl;

	ctrl.algo_mode = algo_mode;
	ctrl.work_mode = work_mode;
	ctrl.oper_mode = FH_CESA_ADES_OPER_MODE_ENCRYPT;
	ctrl.self_key_gen = false;
	if (efusekey)
		ctrl.enKeySrc = FH_CESA_ADES_KEY_SRC_EFUSE;
	else {
		ctrl.enKeySrc = FH_CESA_ADES_KEY_SRC_USER;
		memcpy(ctrl.key, aes_key, 32);
	}
	memcpy(ctrl.iv, aes_iv, 16);
	FH_UNF_CESA_ADES_Config(session, &ctrl);
	FH_UNF_CESA_ADES_Process(session, input_data_phy, hw_data_phy, length);

	if (memcmp(hw_data_vir, sw_data, length) != 0)
		printf("%s : %s enc failed!\n", str_algo_mode, str_work_mode);
	else
		printf("%s : %s enc successful!\n", str_algo_mode, str_work_mode);

	ctrl.oper_mode = FH_CESA_ADES_OPER_MODE_DECRYPT;
	FH_UNF_CESA_ADES_Config(session, &ctrl);
	FH_UNF_CESA_ADES_Process(session, hw_data_phy, hw_data_phy, length);

	if (memcmp(hw_data_vir, input_data_vir, length) != 0)
		printf("%s : %s dec failed!\n", str_algo_mode, str_work_mode);
	else
		printf("%s : %s dec successful!\n", str_algo_mode, str_work_mode);

	FH_UNF_CESA_ADES_Destroy(session);
	FH_UNF_CESA_Close();

	FH_SYS_VmmFree(input_data_phy);
	FH_SYS_VmmFree(hw_data_phy);
	free(sw_data);
}

void DES_PHY_TEST(FH_CESA_ADES_ALGO_MODE_E algo_mode,
		FH_CESA_ADES_WORK_MODE_E work_mode,
		uint8_t efusekey[])
{
	uint8_t des_key[24];
	uint8_t des_iv[8];
	uint32_t length = 1024*1024;

	uint8_t *input_data_vir;
	uint32_t input_data_phy;

	uint8_t *hw_data_vir;
	uint32_t hw_data_phy;

	uint8_t *sw_data;
	uint8_t sw_des_iv[8];
	char *str_algo_mode;
	char *str_work_mode;


	//===================data prepare===================
	switch (algo_mode) {
	case FH_CESA_ADES_ALGO_MODE_DES:
		str_algo_mode = "des";
		break;
	case FH_CESA_ADES_ALGO_MODE_TDES:
		str_algo_mode = "tdes";
		break;
	default:
		printf("DES_TEST algorithm mode illegal\n");
		return;
	}

	switch (work_mode) {
	case FH_CESA_ADES_WORK_MODE_ECB:
		str_work_mode = "ecb";
		break;
	case FH_CESA_ADES_WORK_MODE_CBC:
		str_work_mode = "cbc";
		break;
	case FH_CESA_ADES_WORK_MODE_CFB8:
		str_work_mode = "cfb8";
		break;
	case FH_CESA_ADES_WORK_MODE_OFB:
		str_work_mode = "ofb";
		break;
	default:
		printf("DES_TEST work mode illegal\n");
		return;
	}


	sw_data = malloc(length);
	if (FH_SYS_VmmAlloc(&input_data_phy,
		(void **)(&input_data_vir),
		"aes_data", "", length)
		|| NULL == input_data_vir) {
		printf("Error: malloc input_data vmm size: %dB failed.\n", length);
		return;
	}
	memset(input_data_vir, 0, length);

	if (FH_SYS_VmmAlloc(&hw_data_phy,
		(void **)(&hw_data_vir),
		"aes_data", "", length)
		|| NULL == hw_data_vir) {
		printf("Error: malloc hw_data vmm size: %dB failed.\n", length);
		return;
	}
	memset(hw_data_vir, 0, length);


	if (efusekey)
		memcpy(des_key, efusekey, 24);
	else
		FH_UNF_CESA_Gen_Random_Bytes(24, des_key);
	FH_UNF_CESA_Gen_Random_Bytes(8, des_iv);
	FH_UNF_CESA_Gen_Random_Bytes(length, input_data_vir);

	memcpy(sw_data, input_data_vir, length);
	memcpy(sw_des_iv, des_iv, 8);

	//===================C code===================
	CRYPTO_DES_CONTEX des;
	PCRYPTO_DES_BLOCK_CIPHER c_des = 0;

	if (algo_mode == FH_CESA_ADES_ALGO_MODE_DES) {
		CRYPTO_API_des_init(&des);
		c_des = &(des.c);
		c_des->set_key(c_des, des_key, des_key, des_key, DES_ENCRYPT);
		c_des->buf = sw_des_iv;
	} else {
		CRYPTO_API_tdes_init(&des);
		c_des = &(des.c);
		c_des->set_key(c_des, des_key, des_key+8, des_key+16, DES_ENCRYPT);
		c_des->buf = sw_des_iv;
	}

	switch (work_mode) {
	case FH_CESA_ADES_WORK_MODE_ECB:
		CRYPTO_API_des_ecb_encrypt(c_des, sw_data, length);
		break;
	case FH_CESA_ADES_WORK_MODE_CBC:
		CRYPTO_API_des_cbc_encrypt(c_des, sw_data, length);
		break;
	case FH_CESA_ADES_WORK_MODE_CFB8:
		CRYPTO_API_des_cfb8_encrypt(c_des, sw_data, length);
		break;
	case FH_CESA_ADES_WORK_MODE_OFB:
		CRYPTO_API_des_ofb64_encrypt(c_des, sw_data, length);
		break;
	default:
		break;
	}

	//===================HW code===================
	uint32_t session;

	FH_UNF_CESA_Open();
	FH_UNF_CESA_ADES_Create(&session);
	FH_UNF_CESA_ADES_Addr_Attr(session,
				FH_CESA_ADES_ADDR_ATTR_PHY,
				FH_CESA_ADES_ADDR_ATTR_PHY);

	FH_CESA_ADES_CTRL_S ctrl;

	ctrl.algo_mode = algo_mode;
	ctrl.work_mode = work_mode;
	ctrl.oper_mode = FH_CESA_ADES_OPER_MODE_ENCRYPT;
	ctrl.self_key_gen = false;
	if (efusekey)
		ctrl.enKeySrc = FH_CESA_ADES_KEY_SRC_EFUSE;
	else {
		ctrl.enKeySrc = FH_CESA_ADES_KEY_SRC_USER;
		memcpy(ctrl.key, des_key, 24);
	}
	memcpy(ctrl.iv, des_iv, 8);
	FH_UNF_CESA_ADES_Config(session, &ctrl);
	FH_UNF_CESA_ADES_Process(session, input_data_phy, hw_data_phy, length);

	if (memcmp(hw_data_vir, sw_data, length) != 0)
		printf("%s : %s enc failed!\n", str_algo_mode, str_work_mode);
	else
		printf("%s : %s enc successful!\n", str_algo_mode, str_work_mode);

	ctrl.oper_mode = FH_CESA_ADES_OPER_MODE_DECRYPT;
	FH_UNF_CESA_ADES_Config(session, &ctrl);
	FH_UNF_CESA_ADES_Process(session, hw_data_phy, hw_data_phy, length);

	if (memcmp(hw_data_vir, input_data_vir, length) != 0)
		printf("%s : %s dec failed!\n", str_algo_mode, str_work_mode);
	else
		printf("%s : %s dec successful!\n", str_algo_mode, str_work_mode);

	FH_UNF_CESA_ADES_Destroy(session);
	FH_UNF_CESA_Close();

	FH_SYS_VmmFree(input_data_phy);
	FH_SYS_VmmFree(hw_data_phy);
	free(sw_data);
}

int main(int argc, char *argv[])
{
	uint8_t efusekey[32] = {0x35, 0x46, 0x28, 0x79,
							0x72, 0x89, 0x67, 0x73,
							0x21, 0x57, 0x80, 0x76,
							0x54, 0x70, 0x83, 0x60,
							0x11, 0x22, 0x33, 0x44,
							0x55, 0x66, 0x77, 0x88,
							0x99, 0xaa, 0xbb, 0xcc,
							0xdd, 0xee, 0xff, 0x44};

	SELFKEY_TEST(FH_CESA_ADES_ALGO_MODE_AES128,
		FH_CESA_ADES_WORK_MODE_CBC, NULL);

	SELFKEY_TEST(FH_CESA_ADES_ALGO_MODE_AES128,
		FH_CESA_ADES_WORK_MODE_CBC, efusekey);

	AES_TEST(FH_CESA_ADES_ALGO_MODE_AES128,
		FH_CESA_ADES_WORK_MODE_ECB, NULL);
	AES_TEST(FH_CESA_ADES_ALGO_MODE_AES128,
		FH_CESA_ADES_WORK_MODE_CBC, NULL);
	AES_TEST(FH_CESA_ADES_ALGO_MODE_AES128,
		FH_CESA_AES_WORK_MODE_CTR, NULL);
	AES_TEST(FH_CESA_ADES_ALGO_MODE_AES128,
		FH_CESA_ADES_WORK_MODE_CFB8, NULL);
	AES_TEST(FH_CESA_ADES_ALGO_MODE_AES128,
		FH_CESA_ADES_WORK_MODE_OFB, NULL);

	AES_TEST(FH_CESA_ADES_ALGO_MODE_AES192,
		FH_CESA_ADES_WORK_MODE_ECB, NULL);
	AES_TEST(FH_CESA_ADES_ALGO_MODE_AES192,
		FH_CESA_ADES_WORK_MODE_CBC, NULL);
	AES_TEST(FH_CESA_ADES_ALGO_MODE_AES192,
		FH_CESA_AES_WORK_MODE_CTR, NULL);
	AES_TEST(FH_CESA_ADES_ALGO_MODE_AES192,
		FH_CESA_ADES_WORK_MODE_CFB8, NULL);
	AES_TEST(FH_CESA_ADES_ALGO_MODE_AES192,
		FH_CESA_ADES_WORK_MODE_OFB, NULL);

	AES_TEST(FH_CESA_ADES_ALGO_MODE_AES256,
		FH_CESA_ADES_WORK_MODE_ECB, NULL);
	AES_TEST(FH_CESA_ADES_ALGO_MODE_AES256,
		FH_CESA_ADES_WORK_MODE_CBC, NULL);
	AES_TEST(FH_CESA_ADES_ALGO_MODE_AES256,
		FH_CESA_AES_WORK_MODE_CTR, NULL);
	AES_TEST(FH_CESA_ADES_ALGO_MODE_AES256,
		FH_CESA_ADES_WORK_MODE_CFB8, NULL);
	AES_TEST(FH_CESA_ADES_ALGO_MODE_AES256,
		FH_CESA_ADES_WORK_MODE_OFB, NULL);

	DES_TEST(FH_CESA_ADES_ALGO_MODE_DES,
		FH_CESA_ADES_WORK_MODE_ECB, NULL);
	DES_TEST(FH_CESA_ADES_ALGO_MODE_DES,
		FH_CESA_ADES_WORK_MODE_CBC, NULL);
	DES_TEST(FH_CESA_ADES_ALGO_MODE_DES,
		FH_CESA_ADES_WORK_MODE_CFB8, NULL);
	DES_TEST(FH_CESA_ADES_ALGO_MODE_DES,
		FH_CESA_ADES_WORK_MODE_OFB, NULL);

	DES_TEST(FH_CESA_ADES_ALGO_MODE_TDES,
		FH_CESA_ADES_WORK_MODE_ECB, NULL);
	DES_TEST(FH_CESA_ADES_ALGO_MODE_TDES,
		FH_CESA_ADES_WORK_MODE_CBC, NULL);
	DES_TEST(FH_CESA_ADES_ALGO_MODE_TDES,
		FH_CESA_ADES_WORK_MODE_CFB8, NULL);
	DES_TEST(FH_CESA_ADES_ALGO_MODE_TDES,
		FH_CESA_ADES_WORK_MODE_OFB, NULL);

	AES_TEST(FH_CESA_ADES_ALGO_MODE_AES128,
		FH_CESA_ADES_WORK_MODE_ECB, efusekey);
	AES_TEST(FH_CESA_ADES_ALGO_MODE_AES128,
		FH_CESA_ADES_WORK_MODE_CBC, efusekey);
	AES_TEST(FH_CESA_ADES_ALGO_MODE_AES128,
		FH_CESA_AES_WORK_MODE_CTR, efusekey);
	AES_TEST(FH_CESA_ADES_ALGO_MODE_AES128,
		FH_CESA_ADES_WORK_MODE_CFB8, efusekey);
	AES_TEST(FH_CESA_ADES_ALGO_MODE_AES128,
		FH_CESA_ADES_WORK_MODE_OFB, efusekey);

	AES_TEST(FH_CESA_ADES_ALGO_MODE_AES192,
		FH_CESA_ADES_WORK_MODE_ECB, efusekey);
	AES_TEST(FH_CESA_ADES_ALGO_MODE_AES192,
		FH_CESA_ADES_WORK_MODE_CBC, efusekey);
	AES_TEST(FH_CESA_ADES_ALGO_MODE_AES192,
		FH_CESA_AES_WORK_MODE_CTR, efusekey);
	AES_TEST(FH_CESA_ADES_ALGO_MODE_AES192,
		FH_CESA_ADES_WORK_MODE_CFB8, efusekey);
	AES_TEST(FH_CESA_ADES_ALGO_MODE_AES192,
		FH_CESA_ADES_WORK_MODE_OFB, efusekey);

	AES_TEST(FH_CESA_ADES_ALGO_MODE_AES256,
		FH_CESA_ADES_WORK_MODE_ECB, efusekey);
	AES_TEST(FH_CESA_ADES_ALGO_MODE_AES256,
		FH_CESA_ADES_WORK_MODE_CBC, efusekey);
	AES_TEST(FH_CESA_ADES_ALGO_MODE_AES256,
		FH_CESA_AES_WORK_MODE_CTR, efusekey);
	AES_TEST(FH_CESA_ADES_ALGO_MODE_AES256,
		FH_CESA_ADES_WORK_MODE_CFB8, efusekey);
	AES_TEST(FH_CESA_ADES_ALGO_MODE_AES256,
		FH_CESA_ADES_WORK_MODE_OFB, efusekey);

	DES_TEST(FH_CESA_ADES_ALGO_MODE_DES,
		FH_CESA_ADES_WORK_MODE_ECB, efusekey);
	DES_TEST(FH_CESA_ADES_ALGO_MODE_DES,
		FH_CESA_ADES_WORK_MODE_CBC, efusekey);
	DES_TEST(FH_CESA_ADES_ALGO_MODE_DES,
		FH_CESA_ADES_WORK_MODE_CFB8, efusekey);
	DES_TEST(FH_CESA_ADES_ALGO_MODE_DES,
		FH_CESA_ADES_WORK_MODE_OFB, efusekey);

	DES_TEST(FH_CESA_ADES_ALGO_MODE_TDES,
		FH_CESA_ADES_WORK_MODE_ECB, efusekey);
	DES_TEST(FH_CESA_ADES_ALGO_MODE_TDES,
		FH_CESA_ADES_WORK_MODE_CBC, efusekey);
	DES_TEST(FH_CESA_ADES_ALGO_MODE_TDES,
		FH_CESA_ADES_WORK_MODE_CFB8, efusekey);
	DES_TEST(FH_CESA_ADES_ALGO_MODE_TDES,
		FH_CESA_ADES_WORK_MODE_OFB, efusekey);

	AES_PHY_TEST(FH_CESA_ADES_ALGO_MODE_AES128,
		FH_CESA_ADES_WORK_MODE_CBC, NULL);
	DES_PHY_TEST(FH_CESA_ADES_ALGO_MODE_DES,
		FH_CESA_ADES_WORK_MODE_CBC, NULL);
	DES_PHY_TEST(FH_CESA_ADES_ALGO_MODE_TDES,
		FH_CESA_ADES_WORK_MODE_CBC, NULL);
	AES_PHY_TEST(FH_CESA_ADES_ALGO_MODE_AES128,
		FH_CESA_ADES_WORK_MODE_CBC, efusekey);
	DES_PHY_TEST(FH_CESA_ADES_ALGO_MODE_DES,
		FH_CESA_ADES_WORK_MODE_CBC, efusekey);
	DES_PHY_TEST(FH_CESA_ADES_ALGO_MODE_TDES,
		FH_CESA_ADES_WORK_MODE_CBC, efusekey);
}

